/*
 * Copyright (C) 2022 Lynix
 * @author jianwei.wu (jianwei.wu@lynxi.com)
 * @brief
 * @version 2.0
 * @date 2022-05-09
 *
 * Copyright:
 * © 2018 北京灵汐科技有限公司 版权所有。
 * 注意：以下内容均为北京灵汐科技有限公司原创，未经本公司允许，不得转载，否则将视为侵权；对于不遵守此声明或者其他违法使用以下内容者，本公司依法保留追究权。
 * © 2018 Lynxi Technologies Co., Ltd. All rights reserved.
 * NOTICE: All information contained here is, and remains the property of Lynxi. This file can not be copied or distributed without the permission of Lynxi Technologies Co., Ltd.
 *
 * @par 修改日志:
 * Data: 2022-05-09
 * Author: jianwei.wu
 * Description:
 */

#ifndef __LYN_APU_UAPI_H__
#define __LYN_APU_UAPI_H__

#include <stdint.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C"
{
#endif

typedef void* apu_handle;

enum apu_work_mode_e {
	WORK_MODE_UNKNOW = 0,
	WORK_MODE_SNN,
	WORK_MODE_CNN,
	WORK_MODE_MAX,
};

struct apu_snn_user_load {
	uint64_t *snnLookUpAddr;
	uint64_t *snnDevAddr;
	uint32_t *snn_buf_size;
	uint32_t user_load_size;  
};

enum apu_model_type {
	APU_MODEL_ABC = 0,
	APU_MODEL_OLD,
	APU_MODEL_GEMM,
	APU_MODEL_TOPK,
	APU_MODEL_COSINE,
	APU_MODEL_SNN,
	APU_MODEL_GLM_P2P,
	APU_MODEL_INF_LOOP,
};

enum apu_dummy_output_type {
	DUMMY_OUTPUT_UNDEFINE = 0,
	DUMMY_OUTPUT_FALSE,
	DUMMY_OUTPUT_TRUE
};

enum apu_run_type {
	APU_RUN_DEFAULT = 0, //Combine loadnn and startnn
	APU_RUN_LOADNN,
	APU_RUN_STARTNN,
	APU_RUN_MAX
};

enum apu_state_e {
	APU_IDLE = 0,
	APU_LOAD,
	APU_START,
	APU_LSTART,
	APU_STATE_MAX,
};

struct apu_user_runtime {
	int state;
	uint32_t queue_time;
	uint32_t load_time;
	uint32_t apu_use_time;
	uint32_t total_use_time;
};

struct apu_user_runtime_param {
	int len;
	struct apu_user_runtime *user_runtime;
};

struct gemm_model_param {
	uint64_t N;
	uint64_t K;
	uint64_t *B_phy_addr;
	uint64_t *C_phy_addr;
	float *alpha;
	float *beta;
};

struct topk_run_param {
	int in_k; // 输入数据的 k，不是模型的 K
	uint64_t *in_phy_addrs; // 数组的首地址，该数组存放输入数据所在的每行起始物理地址
	void *index_addrs; // 索引数据的首地址
	uint64_t out_phy_addr;
	uint64_t out_lookup_addr;
	uint64_t index_begin; // 含
	uint64_t index_end; // 不含
};

struct apu_model {
	uint32_t is_folded;			//< 0 or 1, indicates whether the model is folded, which will decides to use 1: 1load+1start or 0: 1load+n_start
	uint32_t timeout;			//< receive timeout(ms)
	uint64_t dat_bin_vaddr;
	uint64_t dat_bin_addr;		//< the physical addr of dat.bin	-->write to ddr 0x880800000
	uint32_t dat_bin_size;		//< the length of dat.bin
	uint64_t core_bin_vaddr;
	uint64_t core_bin_addr;		//< the physical addr of core.bin	-->load
	uint32_t core_bin_size;		//< the length of core.bin
	uint32_t cmd_size;			//< the length of cmd.bin			-->start/loadstart
	char *cmd_data;				//< the content of cmd.bin, virtual address

	uint32_t is_init;			//< 0 or 1, indicates whether the model has init's data to apu	-->load
	uint64_t init_core_bin_vaddr;
	uint64_t init_core_bin_addr;	//< the physical addr of core.bin in init directory
	uint32_t init_core_bin_size;	//< the length of the init core.bin
	uint32_t init_cmd_size;			//< the length of the init cmd.bin
	char *init_cmd_data;			//< the content of init cmd.bin, virtual address

	uint32_t  external_file_num;		//< 需要导入的查找表条目
	uint64_t  *external_src_phy_addr;	//< 查找表原始信息的mmz物理地址
	uint64_t  *external_src_vir_addr;   //< 查找表原始信息的mmz虚拟地址
	uint64_t  *external_dst_phy_addr;   //< 查找表需要拷贝的物理地址
	uint32_t  *external_size; 			//< 查找表需要拷贝的尺寸大小

	uint32_t  resolution_num;				// 可变分辨率模式下，支持的最大档位数
	uint32_t  coremem_res_index_addr;		// every core addr offset
	uint32_t  coremem_res_pc_offset;		//  *((uint32_t*)(coremem_res_index_ddr)) = coremem_res_pc_offset + dynamic resolution index
	uint8_t	  (*core_id)[30];				// 2 dimension array ;[resolution_num][30]   max resolutionNum
	uint64_t (*core_noc_config)[30 * 31];	// 写入每个 core 的 lut 数据
	uint64_t *core_noc_reg_addr;			// 写入每个 core 的 lut 起始地址

	uint32_t  crmem_addr_for_load_base; //sdk和driver1.7.0及以后的版本,dat.bin不再需要拷贝至0x8c0800000, 实现了动态加载的过程, 需要SDK和Driver配合，将dat.bin的物理地址写到CR Core

	uint32_t  batch;			//模型batch参数，留作扩展
	uint32_t  n_slice;			//模型batch方向拆分参数，用于兼容单batch的abc模型

	struct apu_snn_user_load snn_user_load;
	enum apu_model_type model_type;
	enum apu_dummy_output_type dummy_output_type;
};


struct apu_run {
	enum apu_run_type run_type;	//used for LLM，startnn/loadnn
	uint32_t  input_num;	//< 输入addr和step的个数 ,其值默认为1
	uint64_t* input_size;	//< input data size
	uint64_t* input_vaddr;	//< input_vaddr[i] 0: nocache, other cache
	uint64_t* input_addr;   //< 输入数据的地址的指针 (fan.xu 此处要求为数组名或者 &数组第一个对象)
	uint64_t  input_lookupaddr; //input可能使用lookup形式，需要将input_addr写入input_lookupaddr
	int64_t*  input_step;   //< 输入数据的step的指针,其值默认为-1

	uint32_t  output_num;   //< 输出addr和step的个数 ,其值默认为1
	uint64_t* output_size;	//< output data size
	uint64_t* output_vaddr;	//< output_vaddr[i] 0: nocache, other cache
	uint64_t* output_addr;  //< 输出数据的地址的指针
	uint64_t  output_lookupaddr; //output可能使用lookup形式，需要将output_addr写入output_lookupaddr
	int64_t*  output_step;	//< 输出数据的step的指针 ,其值默认为-1

	uint32_t  extra_input_num;
	uint64_t  *extra_input_size;
	uint64_t  *extra_input_vaddr;
	uint64_t  *extra_input_addr;
	uint64_t  *extra_input_lookupaddr;

	uint32_t  extra_output_num;
	uint64_t  *extra_output_size;
	uint64_t  *extra_output_vaddr;
	uint64_t  *extra_output_addr;
	uint64_t  *extra_output_lookupaddr;

	uint32_t  dyn_reso_idx; //< 可变分辨率模式下，具体分辨率的档位值，从0开始计

	uint64_t N;
	uint64_t K;
	uint64_t *B_phy_addr;
	uint64_t *C_phy_addr;
	uint64_t *D_phy_addr;
	void *alpha;
	void *beta;

	struct topk_run_param topk_param;
};

struct apu_rcv {
	uint32_t id;	//< return data id
	int irq_icon;	// 0 is irq 0,1 is irq 1
	int state;		//< return data process result. 0 success, !0 failed (-ENODEV -EFAULT -EINTR -ETIME -ERESTARTSYS)
};

 struct apu_armop_info {
	int input_num;		//lookup input num
	int output_num;		//lookup output num

	uint64_t *lookup_input_json_addr;           //json  长度2
	uint64_t *lookup_input_vir_addr;       //json长度2
	uint64_t *lookup_input_phy_addr;       //json 长度2   *lookup_addr = lookup_input_phy_addr;
	uint64_t *lookup_input_vir_addr_size;

	uint64_t *lookup_output_json_addr;       //json
	uint64_t *lookup_output_vir_addr;       //json
	uint64_t *lookup_output_phy_addr;       //json    *lookup_addr = lookup_input_phy_addr;
	uint64_t *lookup_output_vir_addr_size;
 };

 struct apu_armop_status {
	uint16_t index;   //返回一个index
};

 struct apu_armop_clear {
	/*  for clear phase inter info */
	uint8_t core_id;
	uint8_t channel;
};

struct apu_armop {
	/*apu armop json*/
	uint16_t armop_count; //read from reg to SDK

	/*armop info read from sdk json*/
 	struct apu_armop_info *armop_info;
};

//read/write phyaddr bypass mode
struct apu_dma {
	uint64_t phy_addr;	//< 物理地址
	uint32_t remap_flag;	//< 1: phy_addr做ioremap; 0: 使用APU0初始化的map(0x1000000000 + 偏移0x400000000)
	uint32_t data_len;		//< 数据长度
	char* data;				//< 数据指针
};

//check apu mem config param
struct apu_mem {
	uint32_t core_num;			//< set check cores mem. total core number, 5x6 is 30, 3x3 is 9
	uint32_t check_error_num;	//< return checke error num
};

//apu core busy status
struct apu_usage {
	uint32_t total_core_num;			//< set check cores mem. total core number, 5x6 is 30, 3x3 is 9
	uint32_t busy_core_num;	//< return busy core num
};

//get apu info
struct apu_info {
	char ver_drv[10];	//< driver version
	char ver_so[10];	//< so version
	uint32_t online;	//< apu online
	uint32_t cores;		//< apu total cores
	uint32_t used_cores;//< used cores
	uint32_t status;	//< apu cmddone state
	uint32_t clock;		//< apu clock(unit Hz)
};

struct apu_drv_param {
	int debug;			// driver print level, default 0
	int queue_timeout;	// wait queue empty timeout(ms)
	int run_timeout;	// wait apu cmd done timeout(ms)
};

enum apu_clock {
	APU_CLOCK_200M = 200000000,
	APU_CLOCK_250M = 250000000,
	APU_CLOCK_300M = 300000000,
	APU_CLOCK_350M = 350000000,
	APU_CLOCK_400M = 400000000,
	APU_CLOCK_450M = 450000000,
	APU_CLOCK_500M = 500000000,
	APU_CLOCK_550M = 550000000,
	APU_CLOCK_600M = 600000000,
};

/**
 * @brief open the apu hardware
 *
 * @param[in]  slave_idx apu slave index, 0 or 1, default 0
 * @return apu_handle
 */
apu_handle lyn_apu_open(int32_t slave_idx);

/**
 * @brief close the apu hardware
 *
 * @param[in]  handle the hardware file descriptor generated by lyn_apu_open
 */
void lyn_apu_close(apu_handle handle);

/**
 * @brief set the nn model specific params
 *
 * @param[in]  handle apu haredware handle generated by @see lyn_apu_open
 * @param[in]  params the model specific params
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_set_model(apu_handle handle, struct apu_model *model);

/**
 * @brief start to execute the inference,
 * this function should be blocking callable, which means
 * the depth of the apu task queue should be limited, and if the queue is full, this function should be blocked until
 * the task queue is ready to accept the next task
 *
 * @param[in]  handle the hardware file descriptor generated by lyn_apu_open
 * @param[in]  start the start params
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_run(apu_handle handle, struct apu_run *run);

/**
 * @brief receive the output data
 *
 * @param[in]  handle the hardware file descriptor generated by lyn_apu_open
 * @param[in]  out output status
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_rcv(apu_handle handle, struct apu_rcv *rcv);

/**
 * @param[in]  handle the hardware file descriptor generated by lyn_apu_open
 * @param[in]  start the start params
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_armop_set_jsoninfo(apu_handle handle, struct apu_armop *cfg);

/**
 * @param[in]  handle the hardware file descriptor generated by lyn_apu_open
 * @param[in]  start the start params
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_armop_start(apu_handle handle, struct apu_armop_status *cfg);

/**
 * @param[in]  handle the hardware file descriptor generated by lyn_apu_open
 * @param[in]  out output status
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_armop_done(apu_handle handle, struct apu_armop_clear *cfg);

/**
 *@brief lyn_apu_mmap
 * A successful `mmap' call deallocates any previous mapping for the affected region.
 * @param[in]
 * -handle: if NULL use /dev/mem else use /dev/apu
 * -mem_length: need apply for memory length
 * -mem_offset: memory address(offset to memory base address)
 * Returns NULL errors, addr successful
 */
void *lyn_apu_mmap(apu_handle handle, size_t mem_length, off_t mem_offset);
int lyn_apu_munmap(apu_handle handle, void *addr, size_t mem_length);

int lyn_apu_dma_read(apu_handle handle, struct apu_dma *dma);
int lyn_apu_dma_write(apu_handle handle, struct apu_dma *dma);

/**
 * @brief reset the apu hardware, should be called when the apu runs into exceptional state
 * this function will be defaultedly called in @see lyn_apu_open by driver while high-level
 * sdk will call this function only under exception state
 *
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_reset(apu_handle handle);
/**
 * @brief apu shutdown, diable all apu operations. Notice!!! use with caution.
 *
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_shutdown(apu_handle handle);

int lyn_apu_get_info(apu_handle handle, struct apu_info *info);
int lyn_apu_set_clock(apu_handle handle, uint32_t clock);

int lyn_apu_get_drv_param(apu_handle handle, struct apu_drv_param *drv_param);
int lyn_apu_set_drv_param(apu_handle handle, struct apu_drv_param *drv_param);

/**
 * @brief check apu core mem
 * @param[in]
 * -handle: apu slv instance
 * -core_num: 5x6 is 30, 3x3 is 9
 * @param[out]
 * -null
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_check_core_mem(apu_handle handle, struct apu_mem *mem);

/**
 * @brief get core usage
 * @param[in]
 * -usage apu core usage
 * @param[out]
 * -null
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_get_core_usage(apu_handle handle, struct apu_usage *cfg);

int lyn_apu_set_mode(apu_handle handle, enum apu_work_mode_e mode);

/**
 * @brief get apu time cost
 * @param[in]
 * -runtime_param: get time info 
 * @param[out]
 * -null
 * @return int
 * 0, success
 * !0, failed
 */
int lyn_apu_get_runtime(apu_handle handle, struct apu_user_runtime_param *runtime_param);

/**
 * @brief get_LLM_loop_cnt
 * @param[in]
 * @param[out]
 * 
 * @return uint32_t
 * loop count
 */
uint32_t lyn_apu_get_LLM_loop_cnt(apu_handle handle);

/**
 * @brief get_startnn_flag
 * @param[in]
 * @param[out]
 * -null
 * @return int
 * 0, starnn not ready
 * 1, startnn ready
 */
int lyn_apu_get_startnn_ready(apu_handle handle);

/**
 * @brief get_startnn_flag
 * @param[in]
 * @param[out]
 * -null
 * @return int
 * 0, starnn not done
 * 1, startnn done
 */
int lyn_apu_get_startnn_done(apu_handle handle);
#ifdef __cplusplus
}
#endif

#endif /* __LYN_APU_UAPI_H__ */
